/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package interpretadorportugolvisual.partes;

import br.org.isvi.interpretador.portugol.types.Kind;
import br.org.isvi.interpretador.portugol.types.StringSymbol;
import br.org.isvi.interpretador.portugol.types.Symbol;
import br.org.isvi.interpretador.portugol.types.Variable;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 *
 * @author abraaoisvioliveirasouzadocarmo
 */
public class Memoria {

    public enum Estado {

        ativando_code,
        desativando_code,
        ativando_data,
        desativando_data,
        ativando_stack,
        desativando_stack,
        parado
    };

    public enum EstadoElemnt {

        ativando,
        desativando,
        parado
    };
    Estado estado = Estado.parado;
    long tempoInicial = System.currentTimeMillis();
    float greenLevel = 0;
    float blueLevel = 1;
    float redLevel = 1;
    Data data = new Data();
    Code code = new Code();
    Stack stack = new Stack();

    public void setDataBlock(int varsCount) {

        data.altura = varsCount * 20;
        data.altura = data.altura > 300 ? 300 : data.altura;
    }

    public void desenhar(Graphics g, int x, int y) {


//        g.setColor(new Color(0, greenLevel, 0));
//        g.fillRect(x, y, 200, 400);
        g.setColor(Color.black);
        g.drawRect(x, y, 200, 500);

        g.setColor(Color.BLACK);
        Font font = Font.decode("Monospaced 24");
        g.setFont(font);
        g.drawString("MEMÓRIA", x + 40, y - 5);

        data.desenhar(g, x, y);
        code.desenhar(g, x, y);
        stack.desenhar(g, x, y);
        atualizar();
    }

    public Estado getEstado() {
        return estado;
    }

    public void setEstado(Estado estado) {
        tempoInicial = System.currentTimeMillis();
        this.estado = estado;
    }

    public void atualizar() {
    }

    public void addToData(Variable var) {
        DataElemet d = new DataElemet();

        d.data = var;
        d.estado = EstadoElemnt.ativando;
        d.tempoInicial = System.currentTimeMillis();
        data.elements.put(var.getName(), d);

    }

    public void addToStack(Symbol data) {
        StackElemet d = new StackElemet();

        synchronized (stack) {
            d.label = data;
            d.estado = EstadoElemnt.ativando;
            d.tempoInicial = System.currentTimeMillis();
            stack.elements.add(d);
        }

    }

    public Symbol popStack() {

        synchronized (stack) {
            if (stack.elements.isEmpty()) {
                return null;
            }

            StackElemet d = stack.elements.get(stack.elements.size() - 1);

            d.estado = EstadoElemnt.ativando;
            d.tempoInicial = System.currentTimeMillis();
            d.pop = true;
            return d.label;
        }
    }

    public void setValueData(String key, Symbol value) {
        synchronized (data) {
            this.data.elements.get(key).data.setValue(value);
            this.data.elements.get(key).estado = EstadoElemnt.ativando;
            this.data.elements.get(key).tempoInicial = System.currentTimeMillis();
        }
    }

    public void accessData(String key) {
        synchronized (data) {
            this.data.elements.get(key).estado = EstadoElemnt.ativando;
            this.data.elements.get(key).tempoInicial = System.currentTimeMillis();
        }
    }

    public boolean isDataBusy() {
        boolean ret = false;
        for (DataElemet e : data.elements.values()) {
            ret = e.estado == EstadoElemnt.ativando || e.estado == EstadoElemnt.desativando;

            if (ret) {
                break;
            }
        }

        return ret;
    }

    public boolean isStackBusy() {
        boolean ret = false;
        for (StackElemet e : stack.elements) {
            ret = e.estado == EstadoElemnt.ativando || e.estado == EstadoElemnt.desativando;

            if (ret) {
                break;
            }
        }

        return ret;
    }

    public void readCode() {
        code.estado = EstadoElemnt.ativando;
    }

    public boolean isCodeBusy() {
        boolean ret = code.estado != EstadoElemnt.parado;
        return ret;
    }

    class Data {

        int altura = 300;
        HashMap<String, DataElemet> elements = new HashMap<String, DataElemet>();

        public void atualizar() {
        }

        public void desenhar(Graphics g, int x, int y) {

            int cx = x;
            int cy = y + 180;

            g.setColor(Color.black);
            g.drawRect(cx, cy, 200, altura);

            g.setColor(Color.BLACK);
            Font font = Font.decode("Monospaced 18");
            g.setFont(font);
            g.drawString("DATA", cx + 70, cy + 15);

            int xn = cx + 5;
            int yn = cy + 275;

            synchronized (data) {
                for (DataElemet e : elements.values()) {

                    e.desenhar(g, xn, yn);
                    yn = yn - 20;

                    if (yn < 0) {
                        break;
                    }
                }
            }
        }
    }

    class Code {

        EstadoElemnt estado = EstadoElemnt.parado;
        float colorLevel = 1;
        long tempoInicial;

        public void desenhar(Graphics g, int x, int y) {

            int cx = x;
            int cy = y + 480;

            g.setColor(new Color(colorLevel, colorLevel, 1));
            g.fillRect(cx, cy, 200, 20);
            g.setColor(Color.black);
            g.drawRect(cx, cy, 200, 20);

            g.setColor(Color.BLACK);
            Font font = Font.decode("Monospaced 18");
            g.setFont(font);
            g.drawString("CODE", cx + 70, cy + 15);
            atualizar();
        }

        public void atualizar() {
            long atual = System.currentTimeMillis();

            if ((atual - tempoInicial) >= 200) {
                switch (estado) {
                    case ativando:
                        atualizarAtivando();
                        break;
                    case desativando:
                        atualizarDesativando();
                        break;
                }
            }
        }

        private void atualizarAtivando() {
            long atual = System.currentTimeMillis();

            if ((atual - tempoInicial) >= 50) {
                tempoInicial = atual;
                colorLevel = colorLevel - 0.5f;
            }

            if (colorLevel <= 0) {
                colorLevel = 0;
                estado = EstadoElemnt.desativando;
            }

        }

        private void atualizarDesativando() {
            long atual = System.currentTimeMillis();

            if ((atual - tempoInicial) >= 50) {
                tempoInicial = atual;
                colorLevel = colorLevel + 0.5f;
            }

            if (colorLevel >= 1) {
                colorLevel = 1;
                estado = EstadoElemnt.parado;
            }
        }
    }

    class Stack {

        int altura = 180;
        ArrayList<StackElemet> elements = new ArrayList<StackElemet>();
        StackElemet pop = null;

        public void atualizar() {
        }

        public void desenhar(Graphics g, int x, int y) {

            int cx = x;
            int cy = y;

            g.setColor(Color.black);
            g.drawRect(cx, cy, 200, altura);

            g.setColor(Color.BLACK);
            Font font = Font.decode("Monospaced 18");
            g.setFont(font);
            g.drawString("STACK", cx + 70, cy + 15);

            int xn = cx + 5;
            int yn = cy + 155;
            StackElemet r = null;
            synchronized (stack) {
                for (StackElemet e : elements) {

                    e.desenhar(g, xn, yn);
                    yn = yn - 20;

                    if (yn < 0) {
                        break;
                    }

                    if (e.pop && e.estado == EstadoElemnt.parado) {//POP?
                        r = e;
                    }
                }
            }

            if (r != null) {//POP
                elements.remove(r);
            }
        }
    }

    public class StackElemet {

        int altura = 20;
        Symbol label;
        boolean pop;
        EstadoElemnt estado = EstadoElemnt.parado;
        float colorLevel = 1;
        long tempoInicial;

        public void atualizar() {
            long atual = System.currentTimeMillis();

            if ((atual - tempoInicial) >= 200) {
                switch (estado) {
                    case ativando:
                        atualizarAtivando();
                        break;
                    case desativando:
                        atualizarDesativando();
                        break;
                }
            }
        }

        public void desenhar(Graphics g, int x, int y) {

            int cx = x;
            int cy = y;

            g.setColor(new Color(1, colorLevel, colorLevel));
            g.fillRect(cx, cy, 190, 20);
            g.setColor(Color.black);
            g.drawRect(cx, cy, 190, altura);

            g.setColor(Color.BLACK);
            Font font = Font.decode("Monospaced 13");
            g.setFont(font);

            String saida = "=";

            if (label.getKind() == Kind.VARIAVEL) {
                saida = ((Variable) label).getName().toUpperCase() + "=";
            }

            saida = saida + label.toString().toUpperCase();
            if (saida.length() > 23) {
                saida = saida.substring(0, 20) + "...";
            }

            g.drawString(saida, cx + 3, cy + 13);

            atualizar();
        }

        private void atualizarAtivando() {
            long atual = System.currentTimeMillis();

            if ((atual - tempoInicial) >= 50) {
                tempoInicial = atual;
                colorLevel = colorLevel - 0.5f;
            }

            if (colorLevel <= 0) {
                colorLevel = 0;
                estado = EstadoElemnt.desativando;
            }

        }

        private void atualizarDesativando() {
            long atual = System.currentTimeMillis();

            if ((atual - tempoInicial) >= 50) {
                tempoInicial = atual;
                colorLevel = colorLevel + 0.5f;
            }

            if (colorLevel >= 1) {
                colorLevel = 1;
                estado = EstadoElemnt.parado;
            }
        }
    }

    public class DataElemet {

        int altura = 20;
        Variable data;
        EstadoElemnt estado = EstadoElemnt.parado;
        float colorLevel = 1;
        long tempoInicial;

        public void atualizar() {
            long atual = System.currentTimeMillis();

            if ((atual - tempoInicial) >= 200) {
                switch (estado) {
                    case ativando:
                        atualizarAtivando();
                        break;
                    case desativando:
                        atualizarDesativando();
                        break;
                }
            }
        }

        public void desenhar(Graphics g, int x, int y) {

            int cx = x;
            int cy = y;

            g.setColor(new Color(1, colorLevel, colorLevel));
            g.fillRect(cx, cy, 190, 20);
            g.setColor(Color.black);
            g.drawRect(cx, cy, 190, altura);

            g.setColor(Color.BLACK);
            Font font = Font.decode("Monospaced 13");
            g.setFont(font);

            String saida = data.getName().toUpperCase() + "=" + data.toString();
            if (saida.length() > 23) {
                saida = saida.substring(0, 20) + "...";
            }

            g.drawString(saida, cx + 3, cy + 13);

            atualizar();
        }

        private void atualizarAtivando() {
            long atual = System.currentTimeMillis();

            if ((atual - tempoInicial) >= 50) {
                tempoInicial = atual;
                colorLevel = colorLevel - 0.5f;
            }

            if (colorLevel <= 0) {
                colorLevel = 0;
                estado = EstadoElemnt.desativando;
            }

        }

        private void atualizarDesativando() {
            long atual = System.currentTimeMillis();

            if ((atual - tempoInicial) >= 50) {
                tempoInicial = atual;
                colorLevel = colorLevel + 0.5f;
            }

            if (colorLevel >= 1) {
                colorLevel = 1;
                estado = EstadoElemnt.parado;
            }
        }
    }
}
